package com.longrise.android.downloadImage;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.lang.ref.SoftReference;
import java.lang.ref.WeakReference;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;
import java.util.Comparator;
import java.util.LinkedHashMap;
import java.util.concurrent.ConcurrentHashMap;

import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;


import com.longrise.android.Global;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Color;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.os.AsyncTask;
import android.util.Log;
import android.widget.ImageView;

public class ImageLoader {

    //文件保存的路径
    private static String filepath = null;
    //最大内存
    final static int memClass = (int) Runtime.getRuntime().maxMemory();
    private Context context;
    // 是否缓存到硬盘  
    private boolean diskcache = true;
    // 定义一级 缓存的图片数
    private static final int catch_num = 10;
    // 定义二级缓存 容器  软引用  
    private static ConcurrentHashMap<String, SoftReference<Bitmap>> current_hashmap = new ConcurrentHashMap<String, SoftReference<Bitmap>>();

    // 定义一级缓存容器  强引用(catch_num ,0.75f,true） 默认参数 2.加载因子默认3.排序模式 true                                                                                                                         
    private static LinkedHashMap<String, Bitmap> link_hashmap = new LinkedHashMap<String, Bitmap>(catch_num, 0.75f, true) {

        // 必须实现的方法
        protected boolean removeEldestEntry(java.util.Map.Entry<String, Bitmap> eldest) {
            /**
             * 当一级缓存中 图片数量大于 定义的数量 放入二级缓存中
             */
            if (this.size() > catch_num) {
                // 软连接的方法 存进二级缓存中
                current_hashmap.put(eldest.getKey(), new SoftReference<Bitmap>(eldest.getValue()));
                // 缓存到本地
                cancheToDisk(eldest.getKey(), eldest.getValue());

                return true;
            }
            return false;
        }

        ;
    };

    public ImageLoader(Context context) {
        filepath = context.getCacheDir().getAbsolutePath();
    }

    public static void setFilepath(String filepath) {
        ImageLoader.filepath = filepath;
    }

    public void setDiskcache(boolean diskcache) {
        this.diskcache = diskcache;
    }

    /**
     * 外部调用此方法   进行下载图片
     */
    public void downLoad(String key, ImageView imageView, Context context, ImageLoadListener imageLoadListener) {
        context = this.context;
        // 先从缓存中找  
        Bitmap bitmap = getBitmapFromCache(key);
        if (null != bitmap) {
            if (null != imageLoadListener) {
                imageLoadListener.onImageLoad(imageView, bitmap);
            }
            //imageView.setImageBitmap(bitmap);  
            //取消下载  
            cancleDownload(key, imageView);
            return;
        }

        // 缓存中 没有  把当前的 imageView 给他 得到 task   
        if (cancleDownload(key, imageView)) {
            //没有任务进行。，。。开始下载
            ImageDownloadTask task = new ImageDownloadTask(imageView, imageLoadListener);
            Zhanwei_Image zhanwei_image = new Zhanwei_Image(task);
            //先把占位的图片放进去  
            imageView.setImageDrawable(zhanwei_image);
            // task执行任务  
            task.execute(key);
        }
    }


    /**
     * 此方法 用于优化  ： 用户直接 翻到 哪个 就先加载 哪个
     *
     * @param key       - URL
     * @param imageView - imageView
     *                  core： 给当前的 imageView 得到给他下载的 task
     */

    private boolean cancleDownload(String key, ImageView imageView) {
        // 给当前的 imageView 得到给他下载的 task  
        ImageDownloadTask task = getImageDownloadTask(imageView);
        if (null != task) {
            String down_key = task.key;
            if (null == down_key || !down_key.equals(key)) {
                // imageview 和 url 的key不一样 取消下载
                task.cancel(true);
            } else {
                return false; // 正在下载：
            }
        }
        return true;            //没有正在下载  
    }


//  public void getThisProcessMemeryInfo() {  
//        int pid = android.os.Process.myPid();  
//        android.os.Debug.MemoryInfo[] memoryInfoArray = activityManager.getProcessMemoryInfo(new int[] {pid});  
//        System.out.println("本应用当前使用了" + (float)memoryInfoArray[0].getTotalPrivateDirty() / 1024 + "mb的内存");  
//    }  


    /**
     * 从缓存中得到 图片的方法 1.先从一级 缓存找 linkhashmap 不是线程安全的 必须要加同步
     */
    public Bitmap getBitmapFromCache(String key) {
        //1.先在一级缓存中找
        synchronized (link_hashmap) {
            Bitmap bitmap = link_hashmap.get(key);
            if (null != bitmap) {
                link_hashmap.remove(key);
                // 按照 LRU是Least Recently Used 近期最少使用算法 内存算法 就近 就 原则 放到首位  
                link_hashmap.put(key, bitmap);
                //System.out.println(" 在缓存1中找图片了 =" +key);  
                return bitmap;
            }
        }

        // 2. 到二级 缓存找
        SoftReference<Bitmap> soft = current_hashmap.get(key);
        if (soft != null) {
            //得到 软连接 中的图片  
            Bitmap soft_bitmap = soft.get();
            if (null != soft_bitmap) {
                //System.out.println(" 在缓存2中找图片了 =" +key);  
                return soft_bitmap;
            }
        } else {
            // 没有图片的话 把这个key删除  
            current_hashmap.remove(key);
        }


        //3.都没有的话去从外部缓存文件读取  
        if (diskcache) {
            Bitmap bitmap = getBitmapFromFile(key);
            if (bitmap != null) {
                link_hashmap.put(key, bitmap);   //将图片放到一级缓存首位  
                return bitmap;
            }
        }

        return null;
    }


    /**
     * 缓存到本地文件
     *
     * @param key
     * @param bitmap
     */
    public static void cancheToDisk(String key, Bitmap bitmap) {
        //2.缓存bitmap至/data/data/packageName/cache/文件夹中  
        try {
            String fileName = getMD5Str(key);
            String filePath = filepath + "/" + fileName;
            //System.out.println("缓存到本地===" + filePath);  
            FileOutputStream fos = new FileOutputStream(filePath);
            bitmap.compress(Bitmap.CompressFormat.JPEG, 100, fos);

        } catch (Exception e) {

        }
    }


    /**
     * 从外部文件缓存中获取bitmap
     *
     * @param url
     * @return
     */
    private Bitmap getBitmapFromFile(String url) {
        Bitmap bitmap = null;
        String fileName = getMD5Str(url);
        if (fileName == null) {
            return null;
        }
        String filePath = filepath + "/" + fileName;
        try {
            File file = new File(filePath);
            if (!file.exists()) {
                return null;
            }
            FileInputStream fis = new FileInputStream(filePath);
            bitmap = BitmapFactory.decodeStream(fis);
            // System.out.println("在本地缓存中找到图片==="+ filePath);
        } catch (FileNotFoundException e) {
            // System.out.println("getBitmapFromFile==="+ e.toString());
            e.printStackTrace();
            bitmap = null;
        }
        return bitmap;
    }


    /**
     * 清理文件缓存
     *
     * @param dirPath
     * @return
     */
    public static boolean removeCache(String dirPath) {
        File dir = new File(dirPath);
        File[] files = dir.listFiles();
        if (files == null || files.length == 0) {
            return true;
        }
        int dirSize = 0;
        //这里删除所有的缓存
        int all_ = (int) (1 * files.length + 1);
        //对files 进行排序
        Arrays.sort(files, new FileLastModifiedSort());
        for (int i = 0; i < all_; i++) {
            files[i].delete();
        }
        return true;
    }


    /**
     * 根据文件最后修改时间进行排序
     */
    private static class FileLastModifiedSort implements Comparator<File> {
        @Override
        public int compare(File lhs, File rhs) {
            if (lhs.lastModified() > rhs.lastModified()) {
                return 1;
            } else if (lhs.lastModified() == rhs.lastModified()) {
                return 0;
            } else {
                return -1;
            }
        }
    }


    /**
     * MD5 加密
     */
    private static String getMD5Str(String str) {
        MessageDigest messageDigest = null;
        try {
            messageDigest = MessageDigest.getInstance("MD5");
            messageDigest.reset();
            messageDigest.update(str.getBytes("UTF-8"));
        } catch (NoSuchAlgorithmException e) {
            // System.out.println("NoSuchAlgorithmException caught!");
            return null;
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
            return null;
        }

        byte[] byteArray = messageDigest.digest();
        StringBuffer md5StrBuff = new StringBuffer();
        for (int i = 0; i < byteArray.length; i++) {
            if (Integer.toHexString(0xFF & byteArray[i]).length() == 1)
                md5StrBuff.append("0").append(Integer.toHexString(0xFF & byteArray[i]));
            else md5StrBuff.append(Integer.toHexString(0xFF & byteArray[i]));
        }
        return md5StrBuff.toString();
    }


    // ------------------------ 异步加载----------------------------  

    /**
     * 占位的 图片 或者 颜色      用来绑定 相应的图片
     */
    class Zhanwei_Image extends ColorDrawable {
        //里面存放 相应 的异步 处理时加载好的图片 ----- 相应的 task  
        private final WeakReference<ImageDownloadTask> taskReference;

        public Zhanwei_Image(ImageDownloadTask task) {
            super(Color.BLUE);
            taskReference = new WeakReference<ImageLoader.ImageDownloadTask>(task);
        }

        // 返回去这个 task 用于比较
        public ImageDownloadTask getImageDownloadTask() {
            return taskReference.get();
        }
    }


    // 根据 给 的 iamgeView、 得到里面的 task  用于和当前的 task比较是不是同1个  
    private ImageDownloadTask getImageDownloadTask(ImageView imageView) {
        if (null != imageView) {
            Drawable drawable = imageView.getDrawable();
            if (drawable instanceof Zhanwei_Image) {
                return ((Zhanwei_Image) drawable).getImageDownloadTask();
            }
        }
        return null;
    }


    /**
     * 把图片 添加到缓存中
     */
    public void addBitmap(String key, Bitmap bitmap) {
        if (null != bitmap) {
            synchronized (link_hashmap) {
                // 添加到一级 缓存中
                link_hashmap.put(key, bitmap);
            }
        }
    }


    /**
     * 在后台 加载每个图片
     * 第一个参数 第2个要进度条不 第三个返回结果 bitmap
     */
    class ImageDownloadTask extends AsyncTask<String, Void, Bitmap> {

        private String key;
        //用这第一次加载时种接口对象会被回收掉，原因不知，改用下面这种就OK
        //private WeakReference<ImageView> imgViReference;  
        //private WeakReference<ImageLoadListener> listenerReference;  
        private ImageView imgViReference;
        private ImageLoadListener listenerReference;

        public ImageDownloadTask(ImageView imageView, ImageLoadListener imageLoadListener) {
            //imageView 传进来 。。要给哪个iamgeView加载图片  
            imgViReference = imageView;
            listenerReference = imageLoadListener;
        }

        @Override
        protected Bitmap doInBackground(String... params) {
            key = params[0];
            //调用下载函数 根据 url 下载        
            return downloadBitmap(key);
        }

        @Override
        protected void onPostExecute(Bitmap result) {
            if (isCancelled()) {
                result = null;
            }


            if (null != result) {
                // 保存到缓存中
                addBitmap(key, result);
                //ImageView imageView = imgViReference.get();
                //ImageLoadListener loadListener = listenerReference.get();
                ImageView imageView = imgViReference;
                ImageLoadListener loadListener = listenerReference;
                // 向 imageView 里面放入 bitmap
                ImageDownloadTask task = getImageDownloadTask(imageView);
                /**
                 * 判断 是不是 同一个 task( ) 如果当前这个 task == imageView 里面的那个 task
                 * 就是同1个
                 */
                if (this == task) {
                    if (null != loadListener) {
                        loadListener.onImageLoad(imageView, result);
                    }
                    //imageView.setImageBitmap(result);
                }
            }
        }
    }


    /**
     * 连接网络 客户端 下载图片
     */
    private Bitmap downloadBitmap(String url) {

        //final HttpClient client = AndroidHttpClient.newInstance("Android");  
        final HttpClient client = Global.getInstance().getClient().getHttpClient();
        final HttpGet getRequest = new HttpGet(url);
        try {
            HttpResponse response = client.execute(getRequest);
            final int statusCode = response.getStatusLine().getStatusCode();

            if (statusCode != HttpStatus.SC_OK) {
                Log.w("ImageDownloader", "Error " + statusCode + " while retrieving bitmap from " + url);
                return null;
            }

            final HttpEntity entity = response.getEntity();
            if (entity != null) {
                InputStream inputStream = null;
                try {
                    inputStream = entity.getContent();
                    /**
                     *  1.没有压缩直接将生成的bitmap返回去 
                     */
//                  return BitmapFactory.decodeStream(inputStream);  

                    /**
                     *  2.得到data后在这里把图片进行压缩
                     */
                    byte[] data = StreamTool.read(inputStream);

                    return BitmapManager.scaleBitmap(context, data, 1f);
//                   return BitmapFactory.decodeStream(new FlushedInputStream(inputStream));  
                } finally {
                    if (inputStream != null) {
                        inputStream.close();
                    }
                    entity.consumeContent();
                }
            }
        } catch (IOException e) {
            getRequest.abort();
        } catch (IllegalStateException e) {
            getRequest.abort();
        } catch (Exception e) {
            getRequest.abort();
        } finally {

        }
        return null;
    }

}  
